{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "from common import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "RESULT_JSON = \"/Users/law/repos/viper/results/latency_bw/latency_bw_all.json\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "results_raw = json.loads(open(RESULT_JSON).read())\n",
    "BENCHMARKS =  results_raw[\"benchmarks\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from collections import defaultdict\n",
    "\n",
    "ALL_STORAGE_TYPES = ['dram', 'devdax', 'fsdax']\n",
    "ALL_BM_TYPES = ['seq_read', 'rnd_read', 'seq_write', 'rnd_write', 'seq_grp_write', 'seq_off_write']\n",
    "\n",
    "runs = {bmt: defaultdict(list) for bmt in ALL_BM_TYPES}\n",
    "        \n",
    "def get_bm_type(bm_type_str):\n",
    "    for bmt in ALL_BM_TYPES:\n",
    "        if bmt in bm_type_str:\n",
    "            return bmt\n",
    "    raise RuntimeError(f\"Unknown bm_type: {bm_type_str}\")\n",
    "    \n",
    "def get_storage_type(storage_str):\n",
    "    for st in ALL_STORAGE_TYPES:\n",
    "        if st in storage_str:\n",
    "            return st\n",
    "    raise RuntimeError(f\"Unknown bm_type: {storage_str}\")\n",
    "\n",
    "for bm in BENCHMARKS:\n",
    "    for storage_type in ALL_STORAGE_TYPES:\n",
    "        if storage_type in bm['label']:\n",
    "            bmt = get_bm_type(bm['label'])\n",
    "            runs[bmt][storage_type].append(bm)\n",
    "            break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "FS=20\n",
    "PLOT_TYPES = ['dram', 'devdax']\n",
    "\n",
    "# s2c = {'dram': \"#990000\", 'devdax': \"#404040\", 'fsdax': '#000099'}\n",
    "s2c = {'dram': \"#0080FF\", 'devdax': \"#000000\", 'fsdax': '#000099'}\n",
    "grp2l = {1: '-.', 4: '--', 8: ':', 16: (0, (1, 1, 1, 0, 0, 0)), 32: '-'}\n",
    "pre2l = {True: '-', False: '--'}\n",
    "s2marker = {'dram': '^', 'devdax': ''}\n",
    "MS=10\n",
    "\n",
    "def _plot_basic(data, ax):\n",
    "    for storage_type in PLOT_TYPES:\n",
    "        if storage_type not in data:\n",
    "            continue\n",
    "        entries = data[storage_type][1:]\n",
    "        threads = list(e['threads'] for e in entries)\n",
    "        latencies = list(e['avg_latency_ns'] for e in entries) \n",
    "        ax.plot(threads, latencies, color=s2c[storage_type])\n",
    "        \n",
    "def _plot_prefault(data, ax, print_no_pre):\n",
    "    for storage_type in PLOT_TYPES:\n",
    "        if storage_type not in data:\n",
    "            continue\n",
    "        entries = data[storage_type]\n",
    "        prefault = [e for e in entries if \"-prefault\" in e['label']]\n",
    "        no_prefault = [e for e in entries if \"no_prefault\" in e['label']]\n",
    "        \n",
    "        entries_to_plot = [(prefault, True)]\n",
    "        if print_no_pre:\n",
    "            entries_to_plot.append((no_prefault, False))\n",
    "        \n",
    "        for (es, did_pre) in entries_to_plot:\n",
    "            if not es:\n",
    "                continue\n",
    "            threads = list(e['threads'] for e in es)\n",
    "            latencies = list(e['avg_latency_ns'] for e in es)\n",
    "            label = f\"{get_storage_type(es[0]['label'])} {'pre' if did_pre else 'no-pre'}\"\n",
    "            ax.plot(threads, latencies, label=label, marker=s2marker[storage_type], ms=MS,\n",
    "                    color=s2c[storage_type], linestyle=pre2l[did_pre], lw=3)      \n",
    "        \n",
    "def plot_seq_read(data, ax):\n",
    "    ax.set_title(\"Sequential Read\", fontsize=FS)\n",
    "    _plot_basic(data, ax)\n",
    "\n",
    "def plot_rnd_read(data, ax):\n",
    "    ax.set_title(\"Random Read\", fontsize=FS)\n",
    "    _plot_basic(data, ax)\n",
    "\n",
    "def plot_seq_write(data, ax, print_no_pre):\n",
    "    ax.set_title(\"Sequential Write\", fontsize=FS)\n",
    "    _plot_prefault(data, ax, print_no_pre)        \n",
    "\n",
    "def plot_rnd_write(data, ax, print_no_pre):\n",
    "    ax.set_title(\"Random Write\", fontsize=FS)\n",
    "    _plot_prefault(data, ax, print_no_pre)   \n",
    "    \n",
    "def plot_seq_write_group(data, grp_to_ax, print_no_pre):\n",
    "    for storage_type in PLOT_TYPES:\n",
    "        entries = data[storage_type]\n",
    "        prefault = [e for e in entries if \"-prefault\" in e['label']]\n",
    "        no_prefault = [e for e in entries if \"no_prefault\" in e['label']]\n",
    "        all_write_groups = [1, 4, 8, 16, 32]\n",
    "        write_groups = defaultdict(list)\n",
    "        for es, did_pre in [(prefault, True), (no_prefault, False)]:\n",
    "            for e in es:\n",
    "                for write_grp in all_write_groups:\n",
    "                    if e['label'].endswith(f\"grp_write_{write_grp}\"):\n",
    "                        write_groups[(write_grp, did_pre)].append(e)\n",
    "        \n",
    "        for (wg, did_pre) in sorted(write_groups.keys()):\n",
    "            entries = {storage_type: write_groups[(wg, did_pre)]}\n",
    "            _plot_prefault(entries, grp_to_ax[wg], print_no_pre) \n",
    "            \n",
    "def plot_seq_write_group_1_plot(data, ax):\n",
    "    write_groups = defaultdict(list)\n",
    "    for storage_type in PLOT_TYPES:\n",
    "        entries = data[storage_type]\n",
    "        entries = [e for e in entries if \"-prefault\" in e['label']]\n",
    "        all_write_groups = [1, 4, 8, 16, 32] if storage_type == 'devdax' else [1]\n",
    "        for e in entries:\n",
    "            for write_grp in all_write_groups:\n",
    "                if e['label'].endswith(f\"grp_write_{write_grp}\"):\n",
    "                    write_groups[(write_grp, storage_type)].append(e)\n",
    "        \n",
    "    for (wg, st) in sorted(write_groups.keys()):\n",
    "        entries = write_groups[(wg, st)]\n",
    "        threads = list(e['threads'] for e in entries)\n",
    "        latencies = list(e['avg_latency_ns'] for e in entries)\n",
    "        label = f\"{wg}\"\n",
    "        is_pmem = st == 'devdax'\n",
    "        ax.plot(threads, latencies, label=label if is_pmem else \"DRAM\", \n",
    "                color=s2c[st], linestyle=grp2l[wg] if is_pmem else '-', lw=3,\n",
    "                marker=s2marker[st], ms=MS)\n",
    "    \n",
    "#     ax.text( 6, 250,  '1', fontsize=FS)\n",
    "#     ax.text(14, 200, ' 4', fontsize=FS)\n",
    "#     ax.text(28, 500,  '8', fontsize=FS)\n",
    "#     ax.text(24, 250, '16', fontsize=FS)\n",
    "#     ax.text(30, 140, '32', fontsize=FS)\n",
    "\n",
    "def plot_seq_write_offset(data, ax):\n",
    "    storage_type ='devdax'\n",
    "    entries = data[storage_type]\n",
    "    all_offsets = [0, 1024, 2048, 3072]\n",
    "    offset_groups = defaultdict(list)\n",
    "    for e in entries:\n",
    "        for write_off in all_offsets:\n",
    "            if e['label'].endswith(f\"off_write_{write_off}\"):\n",
    "                offset_groups[write_off].append(e)\n",
    "\n",
    "    data_points = []\n",
    "    for off in sorted(offset_groups.keys()):\n",
    "        entries = offset_groups[off]\n",
    "        data_points.append(list(e['avg_latency_ns'] for e in entries)[-1]) \n",
    "\n",
    "    ax.bar([0, 1, 2, 3], data_points, color='#404040' )# color=s2c[storage_type])\n",
    "    base_lat = data_points[0]\n",
    "    for i, v in enumerate(data_points[1:], 1):\n",
    "        diff = int(((v - base_lat) / base_lat) * 100)\n",
    "        ax.text(i, v - 50, f\"+{diff}%\", fontsize=FS - 2, color='white', ha='center')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 4, figsize=(20, 3.5))\n",
    "(seq_ax, rnd_ax, grp_ax, off_ax) = axes\n",
    "\n",
    "PRINT_NO_PRE = False\n",
    "plot_seq_write(runs['seq_write'], seq_ax, PRINT_NO_PRE)\n",
    "plot_rnd_write(runs['rnd_write'], rnd_ax, PRINT_NO_PRE)\n",
    "plot_seq_write_group_1_plot(runs['seq_grp_write'], grp_ax)\n",
    "plot_seq_write_offset(runs['seq_off_write'], off_ax)\n",
    "\n",
    "for ax in axes:\n",
    "    for tick in ax.xaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(FS)\n",
    "    for tick in ax.yaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(FS)\n",
    "        \n",
    "for ax in (seq_ax, rnd_ax, grp_ax):\n",
    "    ax.set_xlabel(\"# Threads\", fontsize=FS)\n",
    "    ax.set_ylim(0, 800)\n",
    "    ax.set_yticks([0, 200, 400, 600, 800])\n",
    "    ax.set_xticks([1, 4, 8, 16, 32])\n",
    "    ax.grid(axis='y', which='major')\n",
    "\n",
    "off_ax.set_ylim(0, 300)\n",
    "off_ax.set_xticks([0, 1, 2, 3])\n",
    "off_ax.set_xticklabels([0, 1024, 2048, 3072])\n",
    "off_ax.set_title(\"Offset Seq. Write\", fontsize=FS)\n",
    "off_ax.set_xlabel(\"Offset in Byte\", fontsize=FS)\n",
    "off_ax.grid(axis='y', which='major')\n",
    "off_ax.set_axisbelow(True)\n",
    "\n",
    "seq_ax.set_title(\"a) Sequential Write\", fontsize=20, fontweight='bold')\n",
    "rnd_ax.set_title(\"b) Random Write\", fontsize=20, fontweight='bold')\n",
    "grp_ax.set_title(\"c) Grouped Seq. Write\", fontsize=20, fontweight='bold')\n",
    "off_ax.set_title(\"d) Offset Seq. Write\", fontsize=20, fontweight='bold')\n",
    "\n",
    "seq_ax.set_ylabel(\"Latency in ns\", fontsize=FS + 2)\n",
    "# off_ax.set_ylabel(\"Latency in ns\", fontsize=FS)\n",
    "\n",
    "grp_handles, grp_labels = grp_ax.get_legend_handles_labels()\n",
    "grp_labels = [grp_labels[0], grp_labels[2], grp_labels[3], grp_labels[1], grp_labels[4], grp_labels[5]]\n",
    "grp_handles = [grp_handles[0], grp_handles[2], grp_handles[3], grp_handles[1], grp_handles[4], grp_handles[5]]\n",
    "grp_leg = grp_ax.legend(grp_handles, grp_labels, fontsize=18, loc='upper left', ncol=2, \n",
    "                        frameon=True, edgecolor='white', columnspacing=0.4, handletextpad=0.2, \n",
    "                        borderpad=0.1, labelspacing=0.1, handlelength=1.8, facecolor='white', \n",
    "                        framealpha=1, bbox_to_anchor=(-0.02, 1.03))\n",
    "grp_leg.set_zorder(-1)\n",
    "\n",
    "seq_leg = seq_ax.legend(labels=['DRAM', \"PMem\"], fontsize=FS, loc='upper left', frameon=False,\n",
    "                        handletextpad=0.4, borderpad=0.1, handlelength=1.6)\n",
    "\n",
    "for legobj in (*seq_leg.legendHandles, *grp_leg.legendHandles):\n",
    "    legobj.set_linewidth(4.0)\n",
    "\n",
    "\n",
    "for ax in axes:\n",
    "    hide_border(ax, True)\n",
    "    for tick in ax.xaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(20)\n",
    "    for tick in ax.yaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(20)\n",
    "    \n",
    "plt.tight_layout()\n",
    "fig.savefig('charts/design_latency.pdf', bbox_inches='tight')\n",
    "fig.savefig('charts/design_latency.svg', bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## GENERAL OVERVIEW. NOT FOR PAPER PLOT!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "\n",
    "fig, axes = plt.subplots(1, 4, figsize=(20, 3.5))\n",
    "(seq_read_ax, rnd_read_ax, seq_write_ax, rnd_write_ax) = axes\n",
    "\n",
    "grp_fig, grp_axes = plt.subplots(1, 5, figsize=(25, 3.5))\n",
    "(grp1_ax, grp4_ax, grp8_ax, grp16_ax, grp32_ax) = grp_axes\n",
    "grp_to_ax = {1: grp1_ax, 4: grp4_ax, 8: grp8_ax, 16: grp16_ax, 32: grp32_ax}\n",
    "\n",
    "off_fig, off_ax = plt.subplots(1, 1, figsize=(5, 3.5))\n",
    "\n",
    "grp_test_fig, grp_test_ax = plt.subplots(1, 1, figsize=(5, 3.5))\n",
    "plot_seq_write_group_1_plot(runs['seq_grp_write'], grp_test_ax)\n",
    "\n",
    "PRINT_NO_PRE = False\n",
    "plot_seq_read(runs['seq_read'], seq_read_ax)\n",
    "plot_rnd_read(runs['rnd_read'], rnd_read_ax)\n",
    "plot_seq_write(runs['seq_write'], seq_write_ax, PRINT_NO_PRE)\n",
    "plot_rnd_write(runs['rnd_write'], rnd_write_ax, PRINT_NO_PRE)\n",
    "\n",
    "plot_seq_write_offset(runs['seq_off_write'], off_ax)\n",
    "\n",
    "PRINT_NO_PRE = False\n",
    "plot_seq_write_group(runs['seq_grp_write'], grp_to_ax, PRINT_NO_PRE)\n",
    "\n",
    "for ax in (*axes, *grp_axes, off_ax):\n",
    "    for tick in ax.xaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(FS)\n",
    "    for tick in ax.yaxis.get_major_ticks():\n",
    "        tick.label.set_fontsize(FS)\n",
    "        \n",
    "for ax in (*axes, *grp_axes):\n",
    "    ax.set_xlabel(\"# Threads\", fontsize=FS)\n",
    "    ax.set_ylim(0, 800)\n",
    "    ax.set_xticks([1, 4, 8, 16, 32])\n",
    "    ax.grid(axis='y', which='major')\n",
    "\n",
    "off_ax.set_ylim(0, 300)\n",
    "off_ax.set_xticks([0, 1, 2, 3])\n",
    "off_ax.set_xticklabels([0, 1024, 2048, 3072])\n",
    "off_ax.set_title(\"Offset Seq. Write\", fontsize=FS)\n",
    "off_ax.set_xlabel(\"Offset in Byte\", fontsize=FS)\n",
    "\n",
    "for ax in [axes, grp_axes, [off_ax]]:\n",
    "    ax[0].set_ylabel(\"Latency in ns\", fontsize=FS)\n",
    "    \n",
    "fig.legend(labels=[l.upper() for l in PLOT_TYPES], fontsize=FS,\n",
    "    loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol=6, frameon=False,\n",
    "    columnspacing=1.3, handletextpad=0.3)\n",
    "    \n",
    "_, grp_labels = grp_axes[0].get_legend_handles_labels() \n",
    "grp_fig.legend(labels=grp_labels, fontsize=FS,\n",
    "    loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol=6, frameon=False,\n",
    "    columnspacing=1.3, handletextpad=0.3)\n",
    "                \n",
    "for (wg, ax) in grp_to_ax.items():\n",
    "    ax.set_title(f\"{wg}-Grouped Seq. Write\", fontsize=FS)\n",
    "\n",
    "    \n",
    "# fig.savefig('charts/latency_bw.pdf', bbox_inches='tight')\n",
    "# fig.savefig('charts/latency_bw.svg', bbox_inches='tight')\n",
    "# grp_fig.savefig('charts/grp_latency_bw.pdf', bbox_inches='tight')\n",
    "# grp_fig.savefig('charts/grp_latency_bw.svg', bbox_inches='tight')\n",
    "    \n",
    "# fig.savefig('charts/latency_bw_prefault.pdf', bbox_inches='tight')\n",
    "# fig.savefig('charts/latency_bw_prefault.svg', bbox_inches='tight')\n",
    "# grp_fig.savefig('charts/grp_latency_bw_prefault.pdf', bbox_inches='tight')\n",
    "# grp_fig.savefig('charts/grp_latency_bw_prefault.svg', bbox_inches='tight')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
